﻿#include "socket.h"
#include "log.h"

const std::string Socket::defaultip = "127.0.0.1";

Socket::Socket() : m_sockfd(-1) {}

Socket::Socket(int fd) : m_sockfd(fd) {}

Socket::~Socket()
{
    this->close();
}

int Socket::fd() { return m_sockfd; }

bool Socket::create()
{
    m_sockfd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (m_sockfd < 0)
    {
        LOG(Fatal, "CREATE SOCKET FAILED!!");
        return false;
    }
    return true;
}

void Socket::close()
{
    if (m_sockfd != -1)
    {
        ::close(m_sockfd);
        m_sockfd = -1;
    }
}

bool Socket::bind(const std::string &ip, uint16_t port)
{
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = ::htons(port);
    addr.sin_addr.s_addr = ::inet_addr(ip.c_str());
    socklen_t len = sizeof(struct sockaddr_in);
    int ret = ::bind(m_sockfd, (struct sockaddr *)&addr, len);
    if (ret < 0)
    {
        LOG(Fatal, "BIND ADDRESS FAILED!");
        return false;
    }
    return true;
}

bool Socket::listen(int backlog)
{
    int ret = ::listen(m_sockfd, backlog);
    if (ret < 0)
    {
        LOG(Fatal, "SOCKET LISTEN FAILED!");
        return false;
    }
    return true;
}

int Socket::accept()
{
    int newfd = ::accept(m_sockfd, NULL, NULL);
    if (newfd < 0)
    {
        LOG(Warning, "SOCKET ACCEPT FAILED!");
        return -1;
    }
    return newfd;
}

bool Socket::connect(const std::string &ip, uint16_t port)
{
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = ::htons(port);
    addr.sin_addr.s_addr = ::inet_addr(ip.c_str());
    socklen_t len = sizeof(struct sockaddr_in);
    int ret = ::connect(m_sockfd, (struct sockaddr *)&addr, len);
    if (ret < 0)
    {
        LOG(Warning, "CONNECT SERVER FAILED!");
        return false;
    }
    return true;
}

ssize_t Socket::recv(void *buf, size_t size, int flag)
{
    ssize_t ret = ::recv(m_sockfd, buf, size, flag);
    if (ret <= 0)
    {
        if (errno == EAGAIN || errno == EINTR)
        {
            return 0;
        }
        LOG(Warning, "SOCKET RECV FAILED!!, sockfd:%d, ret:%d, errno:%d, %s", m_sockfd, ret, errno, strerror(errno));
        return -1;
    }
    return ret;
}

ssize_t Socket::nonBlockRecv(void *buf, size_t size)
{
    return recv(buf, size, MSG_DONTWAIT);
}

ssize_t Socket::send(const void *buf, size_t size, int flag)
{
    ssize_t ret = ::send(m_sockfd, buf, size, flag);
    if (ret < 0)
    {
        if (errno == EAGAIN || errno == EINTR)
        {
            return 0;
        }
        LOG(Warning, "SOCKET SEND FAILED!!");
        return -1;
    }
    return ret;
}

ssize_t Socket::nonBlockSend(void *buf, size_t size)
{
    if (size == 0)
        return 0;
    return send(buf, size, MSG_DONTWAIT);
}

void Socket::reuseAddress()
{
    int val = 1;
    ::setsockopt(m_sockfd, SOL_SOCKET, SO_REUSEADDR, (void *)&val, sizeof(int));
    val = 1;
    ::setsockopt(m_sockfd, SOL_SOCKET, SO_REUSEPORT, (void *)&val, sizeof(int));
}

void Socket::nonBlock()
{
    int flag = ::fcntl(m_sockfd, F_GETFL, 0);
    ::fcntl(m_sockfd, F_SETFL, flag | O_NONBLOCK);
}

bool Socket::createTcpServer(uint16_t port, const std::string &ip, bool block_flag)
{
    if (create() == false)
        return false;
    if (block_flag)
        nonBlock();
    if (bind(ip, port) == false)
        return false;
    if (listen() == false)
        return false;
    reuseAddress();
    return true;
}

bool Socket::createTcpClient(uint16_t port, const std::string &ip)
{
    if (create() == false)
        return false;
    if (connect(ip, port) == false)
        return false;
    return true;
}
